// Tencent is pleased to support the open source community by making
// 蓝鲸智云 - 监控平台/日志平台 (BlueKing - Monitor/Log) available.
// Copyright (C) 2017-2022 THL A29 Limited, a Tencent company. All rights reserved.
// Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://opensource.org/licenses/MIT
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//

package servicediscoverer

import (
	"net/url"
	"regexp"

	"github.com/TencentBlueKing/bk-collector/processor"
	"github.com/TencentBlueKing/bkmonitor-kits/logger"
)

const (
	SubsetTypeDomain = "domain"
)

type Config struct {
	Subsets []*Subset `config:"subsets" mapstructure:"subsets"`
}

func (c *Config) Setup() {
	for i := 0; i < len(c.Subsets); i++ {
		c.Subsets[i].setup()
	}
}

type Subset struct {
	Type  string        `config:"type" mapstructure:"type"`
	Value string        `config:"value" mapstructure:"value"`
	Rules []*RuleConfig `config:"rules" mapstructure:"rules"`
}

func (s *Subset) setup() {
	for i := 0; i < len(s.Rules); i++ {
		rule := s.Rules[i]
		re, err := regexp.Compile(rule.MatchValue)
		if err != nil {
			logger.Errorf("failed to compile pattern '%s', error: %v", rule.MatchValue, err)
			continue
		}
		rule.re = re
		rule.subsetValue = s.Value
		rule.subsetType = s.Type

		groups := make(map[string]string)
		for _, g := range rule.MatchGroups {
			groups[g.Source] = g.Destination
		}
		rule.groups = groups
	}
}

type MatchGroup struct {
	Source      string `config:"source" mapstructure:"source"`
	Destination string `config:"destination" mapstructure:"destination"`
}

type RuleConfig struct {
	Kind         string       `config:"kind" mapstructure:"kind"`
	PredicateKey string       `config:"predicate_key" mapstructure:"predicate_key"`
	MatchKey     string       `config:"match_key" mapstructure:"match_key"`
	MatchValue   string       `config:"match_value" mapstructure:"match_value"`
	MatchGroups  []MatchGroup `config:"match_groups" mapstructure:"match_groups"`

	re          *regexp.Regexp
	subsetValue string
	subsetType  string
	groups      map[string]string
}

func (rc *RuleConfig) Regexp() *regexp.Regexp    { return rc.re }
func (rc *RuleConfig) SubsetType() string        { return rc.subsetType }
func (rc *RuleConfig) Groups() map[string]string { return rc.groups }

func (rc *RuleConfig) MatchDomain(k string) bool {
	u, err := url.Parse(k)
	if err != nil {
		logger.Errorf("failed to parse url '%s', error: %v", k, err)
		return false
	}
	return rc.subsetValue == u.Host
}

func (rc *RuleConfig) AttributeValue() string {
	df, key := processor.DecodeDimensionFrom(rc.MatchKey)
	if df == processor.DimensionFromAttribute {
		return key
	}
	return ""
}

func (rc *RuleConfig) ResourceValue() string {
	df, key := processor.DecodeDimensionFrom(rc.MatchKey)
	if df == processor.DimensionFromResource {
		return key
	}
	return ""
}

type ConfigHandler struct {
	rules map[string][]*RuleConfig
}

func NewConfigHandler(c *Config) *ConfigHandler {
	rules := make(map[string][]*RuleConfig)
	for i := 0; i < len(c.Subsets); i++ {
		subset := c.Subsets[i]
		for j := 0; j < len(subset.Rules); j++ {
			rule := subset.Rules[j]
			rules[rule.Kind] = append(rules[rule.Kind], rule)
		}
	}

	return &ConfigHandler{rules: rules}
}

func (ch *ConfigHandler) Get(kind string) []*RuleConfig {
	return ch.rules[kind]
}
